﻿using System;
using System.IO;
using System.Reflection;
using log4net;

namespace FileDistributor.IO
{
    public class FileManager
    {
        private readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        public string MoveFile(string sourceFilePath, ProgressState progressState)
        {
            var targetFilePath = string.Empty;

            try
            {
                var sourceDirectorInfo = GetSourceDirectory(sourceFilePath);
                var targetDirectoryInfo = GetTargetDirectory(sourceDirectorInfo, progressState);
                var fileName = Path.GetFileName(sourceFilePath);
                targetFilePath = BuildFilePath(targetDirectoryInfo.FullName, fileName);

                if (File.Exists(targetFilePath))
                {
                    File.Delete(targetFilePath);
                }

                File.Move(sourceFilePath, targetFilePath);
                _logger.Info("File " + sourceFilePath + " moved successfully to " + targetFilePath);
            }
            catch (IOException ex)
            {
                HandleMovieFileException(sourceFilePath, targetFilePath, ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                HandleMovieFileException(sourceFilePath, targetFilePath, ex);
            }

            return targetFilePath;
        }

        private DirectoryInfo GetSourceDirectory(string sourceFilePath)
        {
            var fileInfo = new FileInfo(sourceFilePath);
            var directoryInfo = fileInfo.Directory;

            if (!directoryInfo.Exists)
            {
                throw new IOException("Failed to get directory for path " + sourceFilePath);
            }

            return directoryInfo;
        }

        private DirectoryInfo GetTargetDirectory(DirectoryInfo sourceDirectory, ProgressState progressState)
        {
            string targetDirectoryPath;

            if (progressState == ProgressState.InProgress)
            {
                targetDirectoryPath = BuildPathDirectoryPath(sourceDirectory.FullName, progressState);
            }
            else
            {
                var parentDirectoryInfo = GetParentDirectory(sourceDirectory);
    
                if (progressState == ProgressState.Success)
                {
                    targetDirectoryPath = BuildPathDirectoryPath(parentDirectoryInfo.FullName, progressState);
                }
                else
                {
                    targetDirectoryPath = BuildPathDirectoryPath(parentDirectoryInfo.FullName, progressState);
                }
            }

            var targetDirectoryInfo = new DirectoryInfo(targetDirectoryPath);

            if(!targetDirectoryInfo.Exists)
            {
                targetDirectoryInfo.Create();
            }

            return targetDirectoryInfo;
        }

        private DirectoryInfo GetParentDirectory(DirectoryInfo directory)
        {
            var parentDirectoryInfo = directory.Parent;

            if (parentDirectoryInfo == null || !parentDirectoryInfo.Exists)
            {
                throw new IOException("Failed to get parent directory for directory " + directory.FullName);
            }

            return parentDirectoryInfo;
        }

        private string BuildPathDirectoryPath(string baseDirectoryPath, ProgressState progressState)
        {
            return baseDirectoryPath + @"\" + progressState;
        }

        private string BuildFilePath(string targetDirectoryPath, string fileName)
        {
            return targetDirectoryPath + @"\" + fileName;
        }

        private void HandleMovieFileException(string sourcePath, string targetPath, Exception ex)
        {
            _logger.Error("Failed to move file " + sourcePath + " to directory " + targetPath, ex);
        }
    }
}
